#!/usr/bin/env python3
# split-cmdline - Split swift compiler command lines ------------*- python -*-
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See https://swift.org/LICENSE.txt for license information
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
#
# ----------------------------------------------------------------------------
#
# Split swift compiler command lines into multiple lines.
#
# Reads the command line from stdin and outputs the split line to stdout.
# Example:
#
# $ swiftc -c hello.swift -### | split-cmdline
# /path-to-swift/bin/swift \
#   -frontend \
#   -c \
#   -primary-file hello.swift \
#   -target x86_64-apple-macosx10.9 \
#   -enable-objc-interop \
#   -color-diagnostics \
#   -module-name hello \
#   -o hello.o
#
# Example usage in vim:
# *) make sure that split-cmdline is in the $PATH
# *) copy-paste the swift command line the text buffer
# *) select the command line
# *) go to the command prompt (= press ':')
# :'<,'>!split-cmdline
#
# ----------------------------------------------------------------------------

import os
import re
import shlex
import sys


def main():
    for line in sys.stdin:
        first = True
        is_arg_param = False
        # Handle escaped spaces
        args = shlex.split(line)
        for arg in args:
            if arg == "":
                continue
            if not first:
                # Print option arguments in the same line
                print(" " if is_arg_param else " \\\n  ", end="")
            first = False

            # Expand @ option files
            m = re.match(r"^@(\S+\.txt)$", arg)
            if m:
                cmd_file = m.group(1)
                if os.path.isfile(cmd_file):
                    with open(cmd_file) as f:
                        for ln in f.readlines():
                            for name in ln.rstrip().split(";"):
                                if name != "":
                                    print(name + " \\")
                first = True
                continue

            if " " in arg or ";" in arg:
                print('"' + arg + '"', end="")
            else:
                print(arg, end="")

            # A hard-coded list of options which expect a parameter
            is_arg_param = arg in [
                # This list is generated by scraping --help menus from running:
                #
                #   $ ( \
                #     swift --help;                 \
                #     swift build --help;           \
                #     swift run --help;             \
                #     swift repl --help;            \
                #     swift test --help;            \
                #     swift package --help;         \
                #     swiftc --help;                \
                #     xcrun swift-frontend --help;  \
                #     clang --help;                 \
                #   ) | rg -o -r '$3 $2' -- ' ((-[\w-]+),)? (-[\w-]+) <' \
                #     | sed 's/ *$//' | tr ' ' '\n' \
                #     | sort | uniq \
                #     | grep -v -e '-c$' \
                #     | sed -E 's/(.*)/"\1",/'
                "--analyzer-output",
                "--build-system",
                "--cache-path",
                "--config-path",
                "--configuration",
                "--default-registry-url",
                "--experimental-traits",
                "--explicit-target-dependency-import-check",
                "--filter",
                "--jobs",
                "--manifest-cache",
                "--netrc-file",
                "--num-workers",
                "--package-path",
                "--pkg-config-path",
                "--product",
                "--resolver-fingerprint-checking",
                "--resolver-signing-entity-checking",
                "--sanitize",
                "--scratch-path",
                "--sdk",
                "--security-path",
                "--skip",
                "--specifier",
                "--swift-sdk",
                "--swift-sdks-path",
                "--target",
                "--toolchain",
                "--triple",
                "--xunit-output",
                "-B",
                "-D",
                "-F",
                "-Fsystem",
                "-G",
                "-I",
                "-L",
                "-MF",
                "-MJ",
                "-MQ",
                "-MT",
                "-T",
                "-U",
                "-Xanalyzer",
                "-Xarch_device",
                "-Xarch_host",
                "-Xassembler",
                "-Xcc",
                "-Xclang",
                "-Xcuda-fatbinary",
                "-Xcuda-ptxas",
                "-Xcxx",
                "-Xlinker",
                "-Xopenmp-target",
                "-Xpreprocessor",
                "-Xswiftc",
                "-access-notes-path",
                "-allowable-client",
                "-api-diff-data-dir",
                "-api-diff-data-file",
                "-arcmt-migrate-report-output",
                "-assert-config",
                "-autolink-library",
                "-b",
                "-backup-module-interface-path",
                "-batch-scan-input-file",
                "-blocklist-file",
                "-build-id",
                "-cache-replay-prefix-map",
                "-cas-path",
                "-cas-plugin-option",
                "-cas-plugin-path",
                "-cc1-args",
                "-clang-build-session-file",
                "-clang-scanner-module-cache-path",
                "-clang-target",
                "-compare-to-baseline-path",
                "-const-gather-protocols-file",
                "-coverage-prefix-map",
                "-cxx-isystem",
                "-darwin-target-variant",
                "-darwin-target-variant-triple",
                "-debug-info-format",
                "-debug-prefix-map",
                "-define-availability",
                "-dependency-dot",
                "-dependency-file",
                "-dependency-scan-cache-path",
                "-diagnostic-documentation-path",
                "-diagnostic-style",
                "-digester-breakage-allowlist-path",
                "-digester-mode",
                "-dsym-dir",
                "-dump-api-path",
                "-dump-migration-states-dir",
                "-dump-scope-maps",
                "-dumpdir",
                "-e",
                "-embed-tbd-for-module",
                "-emit-abi-descriptor-path",
                "-emit-api-descriptor-path",
                "-emit-clang-header-path",
                "-emit-const-values-path",
                "-emit-dependencies-path",
                "-emit-digester-baseline-path",
                "-emit-fixits-path",
                "-emit-loaded-module-trace-path",
                "-emit-migrated-file-path",
                "-emit-module-dependencies-path",
                "-emit-module-doc-path",
                "-emit-module-interface-path",
                "-emit-module-path",
                "-emit-module-semantic-info-path",
                "-emit-module-serialize-diagnostics-path",
                "-emit-module-source-info-path",
                "-emit-module-summary-path",
                "-emit-objc-header-path",
                "-emit-reference-dependencies-path",
                "-emit-remap-file-path",
                "-emit-tbd-path",
                "-enable-experimental-feature",
                "-enable-upcoming-feature",
                "-explain-module-dependency",
                "-explain-module-dependency-detailed",
                "-explicit-swift-module-map-file",
                "-export-as",
                "-external-plugin-path",
                "-fdepscan-share-identifier",
                "-file-compilation-dir",
                "-file-prefix-map",
                "-filelist",
                "-fmodules-user-build-path",
                "-framework",
                "-group-info-path",
                "-iapinotes-modules",
                "-iapinotes-path",
                "-idirafter",
                "-iframework",
                "-iframeworkwithsysroot",
                "-imacros",
                "-in-process-plugin-server-path",
                "-include",
                "-include-pch",
                "-index-file-path",
                "-index-store-path",
                "-index-unit-output-path",
                "-index-unit-output-path-filelist",
                "-iprefix",
                "-iquote",
                "-isysroot",
                "-isystem",
                "-isystem-after",
                "-ivfsoverlay",
                "-ivfsstatcache",
                "-iwithprefix",
                "-iwithprefixbefore",
                "-iwithsysroot",
                "-j",
                "-l",
                "-libc",
                "-load-plugin-executable",
                "-load-plugin-library",
                "-locale",
                "-localization-path",
                "-lto-library",
                "-meabi",
                "-mllvm",
                "-mmlir",
                "-module-abi-name",
                "-module-alias",
                "-module-cache-path",
                "-module-can-import",
                "-module-can-import-version",
                "-module-dependency-dir",
                "-module-link-name",
                "-module-name",
                "-mthread-model",
                "-num-threads",
                "-o",
                "-output-file-map",
                "-output-filelist",
                "-package-name",
                "-placeholder-dependency-module-map-file",
                "-plugin-path",
                "-prebuilt-module-cache-path",
                "-primary-file",
                "-primary-filelist",
                "-project-name",
                "-require-explicit-availability-target",
                "-runtime-compatibility-version",
                "-s",
                "-save-optimization-record-passes",
                "-save-optimization-record-path",
                "-scanner-prefix-map",
                "-scanner-prefix-map-sdk",
                "-scanner-prefix-map-toolchain",
                "-sdk",
                "-serialize-breaking-changes-path",
                "-serialize-diagnostics",
                "-serialize-diagnostics-path",
                "-serialized-path-obfuscate",
                "-supplementary-output-file-map",
                "-swift-isa-ptrauth-mode",
                "-swift-module-cross-import",
                "-swift-ptrauth-mode",
                "-swift-version",
                "-sysroot",
                "-target",
                "-target-cpu",
                "-target-min-inlining-version",
                "-target-variant",
                "-tbd-compatibility-version",
                "-tbd-current-version",
                "-tbd-install_name",
                "-tools-directory",
                "-user-module-version",
                "-verify-additional-file",
                "-verify-additional-prefix",
                "-verify-generic-signatures",
                "-vfsoverlay",
                "-visualc-tools-root",
                "-visualc-tools-version",
                "-windows-sdk-root",
                "-windows-sdk-version",
                "-working-directory",
                "-x",
                "-z",
            ] + [
                # This list contains options that do not appear in --help menus:
                "-Xfrontend",
                "-Xllvm",
                "-add_ast_path",
                "-arch",
                "-emit-ir",
                "-emit-sil",
                "-fileno",
                "-import-objc-header",
                "-macosx_version_min",
                "-resource-dir",
                "-rpath",
                "-syslibroot",
                "-target-sdk-version",
                "-target-sdk-name",
            ]
            # Heuristic: options ending in -path expect an argument
            if arg.startswith("-") and arg.endswith("-path"):
                is_arg_param = True
            if arg == "-c" and args[0] == "swift":
                is_arg_param = True

        # Print 2 new lines after each command line
        print("\n")


if __name__ == "__main__":
    main()
